package com.yby.algorithm.lru;

import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LRUCache implements Cache {

    private int size;
    private Map<String, Node> nodeLinkedListMap;
    private LinkedList<Node> nodeLinkedList;
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public LRUCache(int size) {
        this.size = size;
        this.nodeLinkedList = new LinkedList<>();
        this.nodeLinkedListMap = new ConcurrentHashMap<>();
    }

    public LRUCache() {

    }

    @Override
    public boolean put(String key, Object value) {
        this.lock.writeLock().lock();
        try {
            Node newNode = new Node(key, value);
            if (nodeLinkedListMap.containsKey(key)) {
                //缓存命中，取出元素
                Node node = nodeLinkedListMap.get(key);
                //将数据更新到链表最前面
                this.updateAndMoveTOFront(node, newNode);
            } else {
                //缓存未命中，创建节点到链表中
                if (this.nodeLinkedList.size() >= this.size) {
                    //如果缓存容量已用完，执行淘汰策略
                    evictElement();
                }
                this.addItem(newNode);
            }
            if (nodeLinkedList.isEmpty()) {
                return false;
            }
            return nodeLinkedList.getFirst() == newNode;
        } finally {
            this.lock.writeLock().unlock();
        }
    }

    @Override
    public Object get(String key) {
        this.lock.readLock().lock();
        try {
            Node node = nodeLinkedListMap.get(key);
            if (node != null) {
                this.moveToFront(node);
                return node.value;
            }
            return null;
        } finally {
            this.lock.readLock().unlock();
        }
    }

    @Override
    public int size() {
        return nodeLinkedList.size();
    }

    @Override
    public boolean isEmpty() {
        return nodeLinkedList.isEmpty();
    }

    @Override
    public void clear() {
        nodeLinkedList.clear();
        nodeLinkedListMap.clear();
    }

    /**
     * 淘汰策略
     */
    private void evictElement() {
        this.lock.writeLock().lock();
        try {
            Node lastNode = this.nodeLinkedList.getLast();
            this.nodeLinkedList.removeLast();
            this.nodeLinkedListMap.remove(lastNode.key);
        } finally {
            this.lock.writeLock().unlock();
        }
    }

    /**
     * 添加元素
     */
    private void addItem(Node newNode) {
        this.nodeLinkedList.addLast(newNode);
        this.nodeLinkedListMap.put(newNode.key, newNode);
    }

    /**
     * 将当前链表节点数据更新,并移动到链表的最前面
     */
    private void updateAndMoveTOFront(Node node, Node newNode) {
        //将节点从原来的链表删除
        this.nodeLinkedList.remove(node);
        this.nodeLinkedListMap.remove(node.key);

        //将新链表节点加入链表中
        this.nodeLinkedList.addFirst(newNode);
        this.nodeLinkedListMap.put(newNode.key, newNode);
    }

    /**
     * 将当前链表节点数据更新到链表的最前面
     */
    private void moveToFront(Node node) {
        //将节点从原来的链表删除
        this.nodeLinkedList.remove(node);
        //将新链表节点加入链表中
        this.nodeLinkedList.addFirst(node);
    }

    public void forEach() {
        for (Node node : nodeLinkedList) {
            System.out.println(node.key + ":  " + node.value);
        }
    }
}


